home *** CD-ROM | disk | FTP | other *** search
/ SPACE 2 / SPACE - Library 2 - Volume 1.iso / misc / 39 / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-07-17  |  13.3 KB  |  621 lines

  1. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  2. /* main.c - version 1.0.3 */
  3.  
  4. #include <stdio.h>
  5. #ifdef UNIX
  6. #include <signal.h>
  7. #endif
  8. #include "hack.h"
  9.  
  10. #ifdef MSDOS
  11. #    ifdef CHDIR
  12. char orgdir[PATHLEN], *getcwd();
  13. #    endif CHDIR
  14. #endif MSDOS
  15.  
  16. #ifdef QUEST
  17. #define    gamename    "quest"
  18. #else
  19. #define    gamename    "hack"
  20. #endif QUEST
  21.  
  22. extern struct permonst mons[CMNUM+2];
  23. extern char genocided[], fut_geno[];
  24. extern char *getlogin(), *getenv();
  25. extern char plname[PL_NSIZ], pl_character[PL_CSIZ];
  26.  
  27. int (*afternmv)();
  28. int (*occupation)();
  29. char *occtxt;            /* defined when occupation != NULL */
  30.  
  31. int done1();
  32. int hangup();
  33.  
  34. int hackpid;                /* current pid */
  35. int locknum;                /* max num of players */
  36. #ifdef DEF_PAGER
  37. char *catmore;                /* default pager */
  38. #endif DEF_PAGER
  39. #ifdef DGK
  40. extern char hackdir[];
  41. extern int  ramdisk;
  42. char SAVEF[FILENAME];
  43. #else
  44. char SAVEF[PL_NSIZ + 11] = "save/";    /* save/99999player */
  45. #endif DGK
  46. char *hname;        /* name of the game (argv[0] of call) */
  47. char obuf[BUFSIZ];    /* BUFSIZ is defined in stdio.h */
  48.  
  49. extern char *nomovemsg;
  50. extern long wailmsg;
  51.  
  52. main(argc,argv)
  53. int argc;
  54. char *argv[];
  55. {
  56.     register int fd;
  57. #ifdef CHDIR
  58.     register char *dir;
  59.  
  60. #ifdef MSDOS
  61.     if (getcwd(orgdir, sizeof orgdir) == NULL) {
  62.         fprintf(stderr, "hack: current directory path too long\n");
  63.         _exit(1);
  64.     }
  65. #endif MSDOS
  66. #endif CHDIR
  67.  
  68.  
  69. #ifdef CHDIR            /* otherwise no chdir() */
  70.     /*
  71.      * See if we must change directory to the playground.
  72.      * (Perhaps hack runs suid and playground is inaccessible
  73.      *  for the player.)
  74.      * The environment variable HACKDIR is overridden by a
  75.      *  -d command line option (must be the first option given)
  76.      */
  77.  
  78. #ifdef TOS
  79.     dir=NULL;
  80.     if(argc > 1 && !strncmp(argv[1], "-D", 2)) {
  81. #else TOS
  82.     dir = getenv("HACKDIR");
  83.     if(argc > 1 && !strncmp(argv[1], "-d", 2)) {
  84. #endif
  85.         argc--;
  86.         argv++;
  87.         dir = argv[0]+2;
  88.         if(*dir == '=' || *dir == ':') dir++;
  89.         if(!*dir && argc > 1) {
  90.             argc--;
  91.             argv++;
  92.             dir = argv[0];
  93.         }
  94.         if(!*dir)
  95.             error("Flag -d must be followed by a directory name.");
  96.     }
  97. #ifdef DGK
  98.     if (dir != NULL)
  99.         (void) strncpy(hackdir, dir, PATHLEN);
  100.     else
  101.         (void) strcpy(hackdir, orgdir);
  102.     dir = hackdir;
  103.     initoptions();
  104. #endif DGK
  105. #endif CHDIR
  106.  
  107. #ifndef DGK
  108.     /* This is no longer needed as the options are initialized
  109.      * above -dgk
  110.      */
  111.     /*
  112.      * Who am i? Algorithm: 1. Use name as specified in HACKOPTIONS
  113.      *            2. Use $USER or $LOGNAME    (if 1. fails)
  114.      *            3. Use getlogin()        (if 2. fails)
  115.      * The resulting name is overridden by command line options.
  116.      * If everything fails, or if the resulting name is some generic
  117.      * account like "games", "play", "player", "hack" then eventually
  118.      * we'll ask him.
  119.      * Note that we trust him here; it is possible to play under
  120.      * somebody else's name.
  121.      */
  122.     { register char *s;
  123.  
  124.       initoptions();
  125.       if(!*plname && (s = getenv("USER")))
  126.         (void) strncpy(plname, s, sizeof(plname)-1);
  127.       if(!*plname && (s = getenv("LOGNAME")))
  128.         (void) strncpy(plname, s, sizeof(plname)-1);
  129.       if(!*plname && (s = getlogin()))
  130.         (void) strncpy(plname, s, sizeof(plname)-1);
  131.     }
  132. #endif DGK
  133.  
  134.     /*
  135.      * Now we know the directory containing 'record' and
  136.      * may do a prscore().
  137.      */
  138. #ifdef TOS
  139.     if(argc > 1 && !strncmp(argv[1], "-S", 2)) {
  140. #else TOS
  141.     if(argc > 1 && !strncmp(argv[1], "-s", 2)) {
  142. #endif TOS
  143. #ifdef CHDIR
  144.         chdirx(dir,0);
  145. #endif CHDIR
  146.         prscore(argc, argv);
  147.         exit(0);
  148.     }
  149.  
  150.     /*
  151.      * It seems he really wants to play.
  152.      * Remember tty modes, to be restored on exit.
  153.      */
  154.     gettty();
  155.     setbuf(stdout,obuf);
  156.     setrandom();
  157.     startup();
  158.     cls();
  159.     u.uhp = 1;    /* prevent RIP on early quits */
  160.     u.ux = FAR;    /* prevent nscr() */
  161. #ifdef    SIGHUP
  162.     (void) signal(SIGHUP, hangup);
  163. #endif
  164.  
  165.     /*
  166.      * Find the creation date of this game,
  167.      * so as to avoid restoring outdated savefiles.
  168.      */
  169.     gethdate(hname);
  170.  
  171.     /*
  172.      * We cannot do chdir earlier, otherwise gethdate will fail.
  173.      */
  174. #ifdef CHDIR
  175. #ifndef TOS
  176.     chdirx(dir,1);
  177. #endif
  178. #endif CHDIR
  179.  
  180.     /*
  181.      * Process options.
  182.      */
  183.     while(argc > 1 && argv[1][0] == '-'){
  184.         argv++;
  185.         argc--;
  186.         switch(argv[0][1]){
  187. #ifdef WIZARD
  188.         case 'W':
  189. #ifdef MSDOS
  190.             wizard = TRUE;
  191. #else
  192.             if(!strcmp(getlogin(), WIZARD))
  193.                 wizard = TRUE;
  194.             else
  195.                 printf("Sorry.\n");
  196. #endif MSDOS
  197.             break;
  198. #endif WIZARD
  199. #ifdef NEWS
  200.         case 'n':
  201.             flags.nonews = TRUE;
  202.             break;
  203. #endif NEWS
  204. #ifdef TOS
  205.         case 'U':
  206. #else TOS
  207.         case 'u':
  208. #endif
  209.             if(argv[0][2])
  210.               (void) strncpy(plname, argv[0]+2, sizeof(plname)-1);
  211.             else if(argc > 1) {
  212.               argc--;
  213.               argv++;
  214.               (void) strncpy(plname, argv[0], sizeof(plname)-1);
  215.             } else
  216.                 printf("Player name expected after -u\n");
  217.             break;
  218. #ifdef DGK
  219.         /* Person does not want to use a ram disk
  220.          */
  221.         case 'R':
  222.             ramdisk = FALSE;
  223.             break;
  224. #endif DGK
  225.         default:
  226.             /* allow -T for Tourist, etc. */
  227.             (void) strncpy(pl_character, argv[0]+1,
  228.                 sizeof(pl_character)-1);
  229.  
  230.             /* printf("Unknown option: %s\n", *argv); */
  231.         }
  232.     }
  233.  
  234. #ifdef DGK
  235.     set_lock_and_bones();
  236.     copybones(FROMPERM);
  237. #endif DGK
  238.     if(argc > 1)
  239.         locknum = atoi(argv[1]);
  240. #ifdef MAX_NR_OF_PLAYERS
  241.     if(!locknum || locknum > MAX_NR_OF_PLAYERS)
  242.         locknum = MAX_NR_OF_PLAYERS;
  243. #endif MAX_NR_OF_PLAYERS
  244. #ifdef DEF_PAGER
  245.     if(!(catmore = getenv("HACKPAGER")) && !(catmore = getenv("PAGER")))
  246.         catmore = DEF_PAGER;
  247. #endif DEF_PAGER
  248. #ifdef MAIL
  249.     getmailstatus();
  250. #endif MAIL
  251. #ifdef WIZARD
  252.     if(wizard) (void) strcpy(plname, "wizard"); else
  253. #endif WIZARD
  254.     if(!*plname || !strncmp(plname, "player", 4)
  255.             || !strncmp(plname, "games", 4))
  256.         askname();
  257.     plnamesuffix();        /* strip suffix from name; calls askname() */
  258.                 /* again if suffix was whole name */
  259.                 /* accepts any suffix */
  260. #ifdef WIZARD
  261.     if(!wizard) {
  262. #endif WIZARD
  263.         /*
  264.          * check for multiple games under the same name
  265.          * (if !locknum) or check max nr of players (otherwise)
  266.          */
  267. #ifdef UNIX
  268. #ifdef    SIGQUIT
  269.         (void) signal(SIGQUIT,SIG_IGN);
  270. #endif
  271.         (void) signal(SIGINT,SIG_IGN);
  272. #endif UNIX
  273. #ifndef DGK
  274.         /* lock is set in read_config_file -dgk */
  275.         if(!locknum)
  276.             (void) sprintf(lock, "%d%s", getuid(), plname);
  277. #endif DGK
  278.         getlock();    /* sets lock if locknum != 0 */
  279. #ifdef WIZARD
  280.     } else {
  281.         register char *sfoo;
  282. #ifndef DGK
  283.         /* lock is set in read_config_file -dgk */
  284.         (void) strcpy(lock,plname);
  285. #endif DGK
  286.         if(sfoo = getenv("MAGIC"))
  287.             while(*sfoo) {
  288.                 switch(*sfoo++) {
  289.                 case 'n': (void) srand(*sfoo++);
  290.                     break;
  291.                 }
  292.             }
  293.         if(sfoo = getenv("GENOCIDED")){
  294.             if(*sfoo == '!'){
  295.                 register struct permonst *pm = mons;
  296.                 register char *gp = genocided;
  297.  
  298.                 while(pm < mons+CMNUM+2){
  299.                     if(!index(sfoo, pm->mlet))
  300.                         *gp++ = pm->mlet;
  301.                     pm++;
  302.                 }
  303.                 *gp = 0;
  304.             } else
  305.                 (void) strcpy(genocided, sfoo);
  306.             (void) strcpy(fut_geno, genocided);
  307.         }
  308.     }
  309. #endif WIZARD
  310.     setftty();
  311. #ifdef DGK
  312.     strncat(SAVEF, plname, 8);
  313.     strcat(SAVEF, ".sav");
  314.     cls();
  315. #ifdef TOS
  316.     if (saveDiskPrompt(1) && ((fd = open(SAVEF, 0x8000)) >= 0) &&
  317. #else TOS
  318.     if (saveDiskPrompt(1) && ((fd = open(SAVEF, 0)) >= 0) &&
  319. #endif TOS
  320. #else 
  321.     (void) sprintf(SAVEF, "save/%d%s", getuid(), plname);
  322.     regularize(SAVEF+5);        /* avoid . or / in name */
  323.     if((fd = open(SAVEF,0)) >= 0 &&
  324. #endif DGK
  325.        (uptodate(fd) || unlink(SAVEF) == 666)) {
  326. #ifdef UNIX
  327.         (void) signal(SIGINT,done1);
  328. #endif UNIX
  329.         pline("Restoring old save file...");
  330.         (void) fflush(stdout);
  331.         if(!dorecover(fd))
  332.             goto not_recovered;
  333.         pline("Hello %s, welcome to %s!", plname, gamename);
  334.         flags.move = 0;
  335.     } else {
  336. not_recovered:
  337.         fobj = fcobj = invent = 0;
  338.         fmon = fallen_down = 0;
  339.         ftrap = 0;
  340.         fgold = 0;
  341.         flags.ident = 1;
  342.         init_objects();
  343.         u_init();
  344. #ifdef UNIX
  345.         (void) signal(SIGINT,done1);
  346. #endif
  347.         mklev();
  348.         u.ux = xupstair;
  349.         u.uy = yupstair;
  350.         (void) inshop();
  351.         setsee();
  352.         flags.botlx = 1;
  353.         /* Fix bug with dog not being made because a monster
  354.          * was on the level 1 staircase
  355.          */
  356.         {
  357.             struct monst *mtmp;
  358.  
  359.             if (mtmp = m_at(u.ux, u.uy))
  360.                 mnexto(mtmp);
  361.         }
  362.         makedog();
  363.         { register struct monst *mtmp;
  364.           if(mtmp = m_at(u.ux, u.uy)) mnexto(mtmp);    /* riv05!a3 */
  365.         }
  366.         seemons();
  367. #ifdef NEWS
  368.         if(flags.nonews || !readnews())
  369.             /* after reading news we did docrt() already */
  370. #endif NEWS
  371.             docrt();
  372.  
  373.         /* give welcome message before pickup messages */
  374.         pline("Hello %s, welcome to %s!", plname, gamename);
  375.  
  376.         pickup(1);
  377.         read_engr_at(u.ux,u.uy);
  378.         flags.move = 1;
  379.     }
  380.  
  381.     flags.moonphase = phase_of_the_moon();
  382.     if(flags.moonphase == FULL_MOON) {
  383.         pline("You are lucky! Full moon tonight.");
  384.          if(!u.uluck) u.uluck++;
  385.     } else if(flags.moonphase == NEW_MOON) {
  386.         pline("Be careful! New moon tonight.");
  387.     }
  388.     initrack();
  389. #ifdef MSDOS
  390.     /* Help the Microsoft optimizer.  Otherwise main is too large -dgk*/
  391.     moveloop();
  392. }
  393.  
  394. static
  395. moveloop()
  396. {
  397. #endif MSDOS
  398.     for(;;) {
  399.         if(flags.move) {    /* actual time passed */
  400.  
  401.             settrack();
  402.  
  403.             if(moves%2 == 0 ||
  404.               (!(Fast & ~INTRINSIC) && (!Fast || rn2(3)))) {
  405.                 extern struct monst *makemon();
  406.                 movemon();
  407.                 if(!rn2(70))
  408.                     (void) makemon((struct permonst *)0, 0, 0);
  409.             }
  410.             if(Glib) glibr();
  411.             timeout();
  412.             ++moves;
  413.             if(flags.time) flags.botl = 1;
  414.             if(u.uhp < 1) {
  415.                 pline("You die...");
  416.                 done("died");
  417.             }
  418.             if(u.uhp*10 < u.uhpmax && moves-wailmsg > 50){
  419.                 wailmsg = moves;
  420.                 if(u.uhp == 1)
  421.                 pline("You hear the wailing of the Banshee...");
  422.                 else
  423.                 pline("You hear the howling of the CwnAnnwn...");
  424.             }
  425.             if(u.uhp < u.uhpmax) {
  426.                 if(u.ulevel > 9) {
  427.                     if(Regeneration || !(moves%3)) {
  428.                         flags.botl = 1;
  429.                         u.uhp += rnd((int) u.ulevel-9);
  430.                         if(u.uhp > u.uhpmax)
  431.                         u.uhp = u.uhpmax;
  432.                     }
  433.                 } else if(Regeneration ||
  434.                     (!(moves%(22-u.ulevel*2)))) {
  435.                     flags.botl = 1;
  436.                     u.uhp++;
  437.                 }
  438.             }
  439.             if(Teleportation && !rn2(85)) tele();
  440.             if(Searching && multi >= 0) (void) dosearch();
  441.             gethungry();
  442.             invault();
  443.             amulet();
  444.         }
  445.         if(multi < 0) {
  446.             if(!++multi){
  447.                 pline(nomovemsg ? nomovemsg :
  448.                     "You can move again.");
  449.                 nomovemsg = 0;
  450.                 if(afternmv) (*afternmv)();
  451.                 afternmv = 0;
  452.             }
  453.         }
  454.  
  455.         find_ac();
  456. #ifndef QUEST
  457.         if(!flags.mv || Blind)
  458. #endif QUEST
  459.         {
  460.             seeobjs();
  461.             seemons();
  462.             nscr();
  463.         }
  464.         if(flags.botl || flags.botlx) bot();
  465.  
  466.         flags.move = 1;
  467.  
  468.         if(multi >= 0 && occupation) {
  469.             if(monster_nearby())
  470.                 stop_occupation();
  471.             else if ((*occupation)() == 0)
  472.                 occupation = 0;
  473.             continue;
  474.         }
  475.  
  476.         if(multi > 0) {
  477. #ifdef QUEST
  478.             if(flags.run >= 4) finddir();
  479. #endif QUEST
  480.             lookaround();
  481.             if(!multi) {    /* lookaround may clear multi */
  482.                 flags.move = 0;
  483.                 continue;
  484.             }
  485.             if(flags.mv) {
  486.                 if(multi < COLNO && !--multi)
  487.                     flags.mv = flags.run = 0;
  488.                 domove();
  489.             } else {
  490.                 --multi;
  491.                 rhack(save_cm);
  492.             }
  493.         } else if(multi == 0) {
  494. #ifdef MAIL
  495.             ckmailstatus();
  496. #endif MAIL
  497.             rhack((char *) 0);
  498.         }
  499.         if(multi && multi%7 == 0)
  500.             (void) fflush(stdout);
  501.     }
  502. }
  503.  
  504. #ifndef DGK
  505. /* This function is unnecessary and incompatible with the #define
  506.  * of glo(x) in config.h -dgk
  507.  */
  508. glo(foo)
  509. register foo;
  510. {
  511.     /* construct the string  xlock.n  */
  512.     register char *tf;
  513.  
  514.     tf = lock;
  515.     while(*tf && *tf != '.') tf++;
  516.     (void) sprintf(tf, ".%d", foo);
  517. }
  518. #endif DGK
  519.  
  520. /*
  521.  * plname is filled either by an option (-u Player  or  -uPlayer) or
  522.  * explicitly (-w implies wizard) or by askname.
  523.  * It may still contain a suffix denoting pl_character.
  524.  */
  525. askname(){
  526. register int c,ct;
  527.     printf("\nWho are you? ");
  528.     (void) fflush(stdout);
  529.     ct = 0;
  530.     while((c = getchar()) != '\n'){
  531. #ifdef MSDOS
  532.         putch(c);
  533. #endif MSDOS
  534.         if(c == EOF) error("End of input\n");
  535.         /* some people get confused when their erase char is not ^H */
  536.         if(c == '\010') {
  537.             if(ct) ct--;
  538.             continue;
  539.         }
  540.         if(c != '-')
  541.         if(c < 'A' || (c > 'Z' && c < 'a') || c > 'z') c = '_';
  542.         if(ct < sizeof(plname)-1) plname[ct++] = c;
  543.     }
  544.     plname[ct] = 0;
  545.     if(ct == 0) askname();
  546. }
  547.  
  548. /*VARARGS1*/
  549. impossible(s,x1,x2)
  550. register char *s;
  551. {
  552.     pline(s,x1,x2);
  553.     pline("Program in disorder - perhaps you'd better Quit.");
  554. }
  555.  
  556. #ifdef CHDIR
  557. chdirx(dir, wr)
  558. char *dir;
  559. boolean wr;
  560. {
  561.  
  562. #ifdef SECURE
  563.     if(dir                    /* User specified directory? */
  564. #ifdef HACKDIR
  565.            && strcmp(dir, HACKDIR)        /* and not the default? */
  566. #endif HACKDIR
  567.         ) {
  568.         (void) setuid(getuid());        /* Ron Wessels */
  569.         (void) setgid(getgid());
  570.     }
  571. #endif SECURE
  572.  
  573. #ifdef HACKDIR
  574.     if(dir == NULL)
  575.         dir = HACKDIR;
  576. #endif HACKDIR
  577.  
  578.     if(dir && chdir(dir) < 0) {
  579.         perror(dir);
  580.         error("Cannot chdir to %s.", dir);
  581.     }
  582.  
  583. #ifdef DGK
  584.     /* Change the default drive as well.
  585.      */
  586.     chdrive(dir);
  587. #endif DGK
  588.  
  589.     /* warn the player if he cannot write the record file */
  590.     /* perhaps we should also test whether . is writable */
  591.     /* unfortunately the access systemcall is worthless */
  592.     if(wr) {
  593.         register fd;
  594.  
  595.         if(dir == NULL)
  596.         dir = ".";
  597.         if((fd = open(RECORD, 2)) < 0) {
  598. #ifdef DGK
  599.         char tmp[PATHLEN];
  600.  
  601.         strcpy(tmp, dir);
  602.         append_slash(tmp);
  603.         printf("Warning: cannot write %s%s", tmp, RECORD);
  604. #else
  605.         printf("Warning: cannot write %s/%s", dir, RECORD);
  606. #endif DGK
  607.         getret();
  608.         } else
  609.         (void) close(fd);
  610.     }
  611. }
  612. #endif CHDIR
  613.  
  614. stop_occupation()
  615. {
  616.     if(occupation) {
  617.         pline("You stop %s.", occtxt);
  618.         occupation = 0;
  619.     }
  620. }
  621.